﻿#include "metainfo.h"
#include "metaproperty.h"
#include "metafunction.h"
#include "Reflectable.h"
#include "metasignal.h"
#include "metaconstructor.h"

MetaInfo::MetaInfo(IMetaInfoBackend* i)
{
	_d = i? i->shared_from_this():NULL;
}

MetaInfo::MetaInfo()
{
}

IMetaInfoBackend * MetaInfo::GetBackend() const
{
	return _d.get();
}

bool MetaInfo::IsValid() const
{
    return _d != NULL;
}

std::string MetaInfo::ClassName() const
{
    return _d->GetClassName();
}

bool MetaInfo::IsBaseOf(const MetaInfo & other) const
{
	if (!other.IsValid() || !IsValid()) {
		return false;
	}

	auto current = other._d.get();
	auto base = _d.get();

	if (current == base) {
		return false;
	}

	while (current)
	{
		if (current == base) {
			return true;
		}

		current = current->SuperClass();
	}

	return false;
}

void *MetaInfo::Create(void *buffer) const
{
    if(!_d){
        return NULL;
    }

	int conindex = -1;
    const auto &cache = _d->GetCacheData();
	conindex = cache.DefaultConstructor;

	if (conindex == -1) {
		return NULL;
	}

	if (buffer == NULL) {
		buffer = new char[_d->GetSize()];
	}

	const void* args[] = {NULL};

	_d->Create(buffer, conindex, args);
	return buffer;
}

void MetaInfo::Destory(void *target) const
{
    if(!_d){
        return;
    }

	_d->Destory(target);
}

void MetaInfo::Delete(void *target) const
{
    if(!_d){
        return;
    }

	_d->Destory(target);
    free(target);
}

bool MetaInfo::IsDefaultCreatable() const
{
    if(!_d){
        return false;
    }
	return _d->GetCacheData().DefaultConstructor != -1;
}

bool MetaInfo::IsCastable() const
{
	return false;
}

int MetaInfo::Size() const
{
    if(!_d){
        return false;
    }
    return _d->GetSize();
}

bool MetaInfo::operator ==(const MetaInfo &info) const
{
    return _d == info._d;
}

MetaConstructor MetaInfo::GetConstructor(int index) const
{
	if (!_d) {
		return MetaConstructor();
	}

	if (index >= 0 && index < _d->NumberOfConstructor())
	{
		return MetaConstructor(_d.get(), index);
	}

	return MetaConstructor();
}

int MetaInfo::ConstructorCount() const
{
	if (!_d) {
		return 0;
	}
	return _d->NumberOfConstructor();
}

int MetaInfo::IndexOfConstructor(const char * signature) const
{
	if (!_d) {
		return -1;
	}

	auto current = _d.get();

	std::string name;
	std::vector<MetaTypeId> types;
	bool ok = ReflectUtils::ParseSignature(signature, name, types);
	if (!ok) {
		return -1;
	}

	return IndexOfConstructor(types);
}

int MetaInfo::IndexOfConstructor(const std::vector<MetaTypeId>& argTypes) const
{
	if (!_d) {
		return -1;
	}
	auto current = _d.get();

	int cnt = current->NumberOfConstructor();
	for (int i = 0; i < cnt; i++) {
		MetaConstructorInfo info = current->GetConstructorInfo(i);
		if (info.ArgTypes == argTypes) {
			return i;
		}
	}

	return -1;
}

MetaFunction MetaInfo::GetFunction(int index) const
{
	if (!_d) {
		return MetaFunction();
	}

	if (index >= 0 && index < _d->NumberOfFunctions() + _d->GetCacheData().FunBegin)
	{
		return MetaFunction(_d.get(), index);
	}

    return MetaFunction();
}

int MetaInfo::FunctionCount() const
{
    if(!_d){
        return 0;
    }
    return _d->GetCacheData().FunBegin + _d->NumberOfFunctions();
}

int MetaInfo::IndexOfFunction(const char *signature) const
{
    if(!_d){
        return -1;
    }

	auto current = _d.get();

	std::string name;
	std::vector<MetaTypeId> types;
	bool ok = ReflectUtils::ParseSignature(signature,name,types);
	if (!ok) {
		return -1;
	}


	return IndexOfFunction(name.c_str(),types);
}

int MetaInfo::IndexOfFunction(const char * functionName, const std::vector<MetaTypeId>& argTypes) const
{
	if (!_d) {
		return -1;
	}

	auto current = _d.get();
	while (current)
	{
		int cnt = current->NumberOfFunctions();
		for (int i = 0; i < cnt; i++) {
			MetaFunctionInfo info = current->GetFunctionInfo(i);
			if (info.Name == functionName && info.ArgTypes == argTypes) {
				return i + current->GetCacheData().FunBegin;
			}
		}
		current = current->SuperClass();
	}
}

int MetaInfo::FunctionBeginIndex() const
{
    if(!_d){
        return -1;
    }

    return _d->GetCacheData().FunBegin;
}

MetaProperty MetaInfo::GetProperty(int index) const
{
	if (!_d) {
		return MetaProperty();
	}

	if (index >= 0 && index < _d->NumberOfFunctions() + _d->GetCacheData().FunBegin)
	{
		return MetaProperty(_d.get(), index);
	}

	return MetaProperty();
}

int MetaInfo::PropertyCount() const
{
    if(!_d){
        return 0;
    }

	return _d->NumberOfPropertys() + _d->GetCacheData().PropBegin;
}

int MetaInfo::IndexOfProperty(const char *propertyName) const
{
	if (!_d) {
		return -1;
	}

	auto current = _d.get();

	while (current)
	{
		int cnt = current->NumberOfPropertys();
		for (int i = 0; i < cnt; i++) {
			MetaPropertyInfo info = current->GetPropertyInfo(i);
			if (propertyName == info.Name) {
				return i + current->GetCacheData().PropBegin;
			}
		}
		current = current->SuperClass();
	}

	return -1;
}

int MetaInfo::PropertyBeginIndex() const
{
    if(!_d){
        return NULL;
    }

    return _d->GetCacheData().PropBegin;
}

MetaSignal MetaInfo::GetSignal(int index) const
{
	if (!_d) {
		return MetaSignal();
	}

	if (index >= 0 && index < _d->NumberOfSignals() + _d->GetCacheData().SignalBegin)
	{
		return MetaSignal(_d.get(), index);
	}

	return MetaSignal();
}

int MetaInfo::SignalCount() const
{
    if(!_d){
        return 0;
    }
    return _d->GetCacheData().SignalBegin + _d->NumberOfSignals();
}

int MetaInfo::IndexOfSignal(const char * signature) const
{
	if (!_d) {
		return -1;
	}

	auto current = _d.get();
	std::string name;
	std::vector<MetaTypeId> types;
	bool ok = ReflectUtils::ParseSignature(signature, name, types);
	if (!ok) {
		return -1;
	}
	while (current)
	{
		int cnt = current->NumberOfSignals();
		for (int i = 0; i < cnt; i++) {
			MetaSignalInfo info = current->GetSignalInfo(i);
			if (info.Name == name && info.ArgTypes == types) {
				return i + current->GetCacheData().SignalBegin;
			}
		}
		current = current->SuperClass();
	}

	return -1;
}

int MetaInfo::IndexOfSinal(const char * name, const std::vector<MetaTypeId>& argTypes) const
{
	return IndexOfSignal(ReflectUtils::GetSignature(name, argTypes).c_str());
}

int MetaInfo::SignalBeginIndex() const
{
    if(!_d){
        return -1;
    }

    return _d->GetCacheData().SignalBegin;
}

std::vector<std::string> MetaInfo::GetClassInfo() const
{
	if (!_d) {
		return {};
	}
	return _d->GetClassInfos();
}

bool MetaInfo::CanMetaCast() const
{
	if (!_d) {
		return false;
	}

	return _d->isCastable();
}

Reflectable *MetaInfo::MetaCast(void * o) const
{
	if (!_d) {
		return NULL;
	}

	if (!_d->isCastable())
	{
		return NULL;
	}

	return _d->MetaCast(o);
}

IMetaInfoBackend::IMetaInfoBackend(IMetaInfoBackend * SuperClass)
{
	m_SuperClass = SuperClass? SuperClass->shared_from_this():NULL;
}

IMetaInfoBackend::CacheData IMetaInfoBackend::GetCacheData() const
{
	return cacheData;
}

void IMetaInfoBackend::CalculateCacheData()
{
	if (m_SuperClass) {
		cacheData.FunBegin = m_SuperClass->GetCacheData().FunBegin + m_SuperClass->NumberOfFunctions();
		cacheData.PropBegin = m_SuperClass->GetCacheData().PropBegin + m_SuperClass->NumberOfPropertys();
		cacheData.SignalBegin = m_SuperClass->GetCacheData().SignalBegin + m_SuperClass->NumberOfSignals();
	}

	for (int i = 0; i < NumberOfConstructor(); i++) {
		auto&& info = GetConstructorInfo(i);
		if (info.ArgTypes.empty()) {
			cacheData.DefaultConstructor = i;
			break;
		}
	}
}

IMetaInfoBackend * IMetaInfoBackend::ToLocalFunction(int index, IMetaInfoBackend * meta, int & localIndex)
{
	auto current = meta;

	localIndex = -1;
	while (current)
	{
		int begin = current->GetCacheData().FunBegin;
		if (begin <= index) {
			localIndex = index - begin;
			return current;
		}

		current = current->SuperClass();
	}


	return nullptr;
}

IMetaInfoBackend * IMetaInfoBackend::ToLocalProperty(int index, IMetaInfoBackend * meta, int & localIndex)
{
	auto current = meta;

	localIndex = -1;
	while (current)
	{
		int begin = current->GetCacheData().PropBegin;
		if (begin <= index) {
			localIndex = index - begin;
			return current;
		}

		current = current->SuperClass();
	}


	return nullptr;
}

IMetaInfoBackend * IMetaInfoBackend::ToLocalSignal(int index, IMetaInfoBackend * meta, int & localIndex)
{
	auto current = meta;

	localIndex = -1;
	while (current)
	{
		int begin = current->GetCacheData().SignalBegin;
		if (begin <= index) {
			localIndex = index - begin;
			return current;
		}

		current = current->SuperClass();
	}


	return nullptr;
}

IMetaInfoBackend * IMetaInfoBackend::SuperClass() const
{
	return m_SuperClass.get();
}
